package com.example.blog.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.blog.common.CustomException;
import com.example.blog.common.Result;
import com.example.blog.dto.UserLoginDTO;
import com.example.blog.dto.UserQuery;
import com.example.blog.entity.SysUser;
import com.example.blog.entity.vo.PageVO;
import com.example.blog.entity.vo.SysUserVO;
import com.example.blog.enums.RoleType;
import com.example.blog.enums.StatusType;
import com.example.blog.mapper.SysUserMapper;
import com.example.blog.util.JwtUtils;
import com.example.blog.util.PasswordUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.Date;
import java.util.HashMap;
import java.util.List;

/**
 * <p>
 * 用户信息表 前端控制器
 * </p>
 *
 * @author 程序员逐梦
 * @since 2023-05-27
 */
@Api(value = "用户接口", tags = "用户相关接口")
@RestController
@RequestMapping("/sysUser")
public class SysUserController extends BaseController {

    @Autowired
    SysUserMapper userMapper;

    /**
     *  查询用户列表
     */
    @ApiOperation(value = "查询用户列表", notes = "查询全部的用户列表")
    @GetMapping("/list")
    public Result<?> getUserList() {
        return new Result<>().success(sysUserService.list());
    }

    /**
     * 通过 id 查询用户
     */
    @ApiOperation(value = "通过id查询用户", notes = "通过id查询单个用户")
    @GetMapping("/getbyid")
    @ApiImplicitParams({
            // name->参数名, value->参数的意义, dataType->参数类型
            @ApiImplicitParam(name = "id", value = "用户id", dataType = "long",
                    // paramType->参数传递类型(query string), required = true -> 表示必传参数,  defaultValue -> 参数默认值
                    paramType = "query", required = true)
    })
    public Result<SysUser> getById(@Param("id") Long id) {
        Result<SysUser> result = new Result<>();
        if (id == null || id <= 0) {
            return result.error(-1, "参数非法");
        }
        // todo: 管理员登录才可以查询, token 直接不放行该接口即可, session

        return result.success(sysUserService.getById(id));
    }

    /**
     *  用户分页查询
     */
    @ApiOperation("分页查询用户列表")
    @PostMapping("/page")
    public Result<PageVO<SysUser>> getUserByPage(@RequestBody UserQuery userQuery) {

        // 查询结果降序排列, 且支持用户名模糊查询
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        if (!"".equals(userQuery.getUsername()) && userQuery.getUsername() != null) {
            // 模糊查询: where %username% like ?
            wrapper.like(SysUser::getUsername, userQuery.getUsername());
        }
        // id 降序排列
        wrapper.orderByDesc(SysUser::getId);

        // 设置默认页码
        if (userQuery.getPageNum() == null || userQuery.getPageNum() < 1) {
            userQuery.setPageNum(1);
        }
        // 设置默认每页最大条数
        if (userQuery.getPageSize() == null || userQuery.getPageSize() < 1) {
            userQuery.setPageSize(20);
        }

        Page<SysUser> page = sysUserService.page(
                new Page<>(
                        userQuery.getPageNum() ,
                        userQuery.getPageSize()
                ),
                wrapper
        );
        return new Result<PageVO<SysUser>>().success(new PageVO<>(page));
    }

    /**
     *  用户登录
     */
    @ApiOperation(value = "用户登录", notes = "用户登录")
    @PostMapping("/login") // @Validated 加上该注解, 实体类的相关变量的校验才会起作用
    public Result<?> login(@Validated @RequestBody UserLoginDTO user) {
        if (!StringUtils.hasLength(user.getUsername())
                || !StringUtils.hasLength(user.getPassword())) {
            return new Result<>().error(-1, "非法操作!");
        }

//        String userStr = "^(?![a-zA-z]+$)(?!\\d+$)(?![!@#$%^&*]+$)[a-zA-Z\\d!@#$%^&*]+$";
//        if (!user.getUsername().matches(userStr)) {
//            return new Result<>().error(-1, "用户名必须由数字,字母,字符任意两种组成,不能含空格");
//        }
//        String str = "^(?![0-9]+$)(?![a-zA-Z]+$)(?![0-9a-zA-Z]+$)(?![0-9\\W]+$)(?![a-zA-Z\\W]+$)[0-9A-Za-z\\W]{6,18}$";
//        if (!user.getPassword().matches(str)) {
//            return new Result<>().error(-1, "密码必须由数字,字母,字符三种组成,且不包括空格");
//        }

        // 查看当前用户名是否存在
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUser::getUsername, user.getUsername());
        SysUser sysUser = sysUserService.getOne(wrapper);
        if (sysUser == null) {
            return new Result<>().error(-1, "用户名或密码错误");
        }
        System.out.println(sysUser.getId());
        if (sysUser.getId() > 0) {
            // 状态state是否正常
            if (sysUser.getStatus() != StatusType.Yes) {
                throw new CustomException(404,"账号已被锁定!");
                // return new Result<>().error("账号已被锁定");
            }
            // 判断密码是否正确
            if (PasswordUtils.check(user.getPassword(), sysUser.getPassword())) {
                // todo:  验证码是否正确
                // 密码正确, 生成jwt / 设置session
                String token = JwtUtils.generateToken(sysUser);
                HashMap<String, Object> result = new HashMap<>();
                result.put("token", token);
                result.put("username", sysUser.getUsername());
                result.put("email", sysUser.getEmail());
                result.put("roleType", sysUser.getRoleType());

                return new Result<>().success(result);
            }
        }
        throw new CustomException(-1,"用户名或密码错误!");
        // return new Result<>().error("用户名或密码错误");
    }

    /**
     *  用户注册
     */
    @ApiOperation(value = "用户注册", notes = "用户注册")
    @PostMapping("/reg") // @Validated 加上该注解, 实体类的相关变量的校验才会起作用
    public Result<?> reg(@Validated @RequestBody UserLoginDTO user) {
        if (user == null || !StringUtils.hasLength(user.getUsername())
                || !StringUtils.hasLength(user.getPassword())) {
            return new Result<>().error(-1, "非法操作!");
        }

        int usernameLen = user.getUsername().length();
        int passwordLen = user.getPassword().length();
        if (usernameLen < 6 || usernameLen > 20) {
            return new Result<>().error(-1, "用户名长度为[6 - 18]位");
        }
        if (passwordLen < 6 || passwordLen > 20) {
            return new Result<>().error(-1, "密码长度为[6 - 18]位");
        }

//        String userStr = "^(?![a-zA-z]+$)(?!\\d+$)(?![!@#$%^&*]+$)[a-zA-Z\\d!@#$%^&*]+$";
//        if (!user.getUsername().matches(userStr)) {
//            return new Result<>().error(-1, "用户名必须由数字,字母,字符任意两种组成,不能含空格");
//        }
//        String str = "^(?![0-9]+$)(?![a-zA-Z]+$)(?![0-9a-zA-Z]+$)(?![0-9\\W]+$)(?![a-zA-Z\\W]+$)[0-9A-Za-z\\W]{6,18}$";
//        if (!user.getPassword().matches(str)) {
//            return new Result<>().error(-1, "密码必须由数字,字母,字符三种组成,且不包括空格");
//        }

        // 查看当前用户名是否存在
        HashMap<String, Object>  map = new HashMap<>();
        map.put("username", user.getUsername());
        List<SysUser> sysUser =  userMapper.selectByMap(map);
        if (sysUser.size() != 0) {
            System.out.println("11l李家强: " + sysUser);
            return new Result<>().error(-1, "用户名已注册");
        }

        // 设置创建时间
        // user.setCreateTime(LocalDateTime.now());
        // 密码加盐处理:
        user.setPassword(PasswordUtils.encrypt(user.getPassword()));
        // save 对应插入语句
        SysUser user1 = new SysUser();
        BeanUtils.copyProperties(user, user1);
        // 设置用户权限
        user1.setRoleType(RoleType.ROLE_USER);
        boolean flag = sysUserService.save(user1);
        if (flag) {
            System.out.println(user.getPassword());
            return new Result<>().success();
        } else
            return new Result<>().error();
    }

    /**
     *  修改用户信息
     */
    @ApiOperation(value = "通过id修改用户信息", notes = "通过id修改用户信息")
    @PostMapping("/update")
    public Result<?> update(@RequestBody SysUser user) {
        if (user == null ){
            return new Result<>().error(-1, "非法操作!");
        }

        // todo: 登录状态拦截.(session) -> token 不用

        int usernameLen = user.getUsername().length();
        int passwordLen = user.getPassword().length();
        if (usernameLen < 6 || usernameLen > 20) {
            return new Result<>().error(-1, "用户名长度为[6 - 18]位");
        }
        if (passwordLen < 6 || passwordLen > 20) {
            return new Result<>().error(-1, "密码长度为[6 - 18]位");
        }
//        if (StringUtils.hasLength(user.getUsername())) {
//            String userStr = "^(?![a-zA-z]+$)(?!\\d+$)(?![!@#$%^&*]+$)[a-zA-Z\\d!@#$%^&*]+$";
//            if (!user.getUsername().matches(userStr)) {
//                return new Result<>().error(-1, "用户名必须由数字,字母,字符任意两种组成,不能含空格");
//            }
//        }

        if (StringUtils.hasLength(user.getPassword())) {
            String str =
                    "^(?![0-9]+$)(?![a-zA-Z]+$)(?![0-9a-zA-Z]+$)(?![0-9\\W]+$)(?![a-zA-Z\\W]+$)[0-9A-Za-z\\W]{6,18}$";
            if (!user.getPassword().matches(str)) {
                return new Result<>().error(-1, "密码必须由数字,字母,字符三种组成,且不包括空格");
            }
        }

        LambdaUpdateWrapper<SysUser> wrapper = new LambdaUpdateWrapper<SysUser>()
                .eq(SysUser::getId, user.getId()) // sql: where id = #{id}
                .set(StringUtils.hasLength(user.getUsername()), SysUser::getUsername, user.getUsername())
                .set(StringUtils.hasLength(user.getPassword()), SysUser::getPassword, user.getPassword())
                .set(StringUtils.hasLength(user.getAddress()), SysUser::getAddress, user.getAddress())
                .set(StringUtils.hasLength(user.getEmail()), SysUser::getEmail, user.getEmail())
                .set(StringUtils.hasLength(user.getAvatarUrl()), SysUser::getAvatarUrl, user.getAvatarUrl())
                .set(StringUtils.hasLength(user.getMobile()), SysUser::getMobile, user.getMobile())
                .set(StringUtils.hasLength(user.getMotto()), SysUser::getMotto, user.getMotto())
                .set(StringUtils.hasLength(user.getSalt()), SysUser::getSalt, user.getSalt())
                .set(user.getRoleType() != null, SysUser::getRoleType, user.getRoleType())
                .set(user.getViews() != null, SysUser::getViews, user.getViews())
                .set(user.getStatus() != null, SysUser::getStatus, user.getStatus())
                .set(SysUser::getUpdateTime, new Date());

        // 设置更新时间: 我不知道为什么自动填充会失效
        Date oldDate = user.getUpdateTime();
        user.setUpdateTime(new Date());
        boolean flag = sysUserService.update(wrapper);
        if (flag) {
            System.out.println("更新成功!");
            return new Result<>().success();
        }
        else {
            System.out.println("更新失败!");
            user.setUpdateTime(oldDate);
            return new Result<>().error();
        }
    }

    /**
     *  通过id 删除用户
     */
    @ApiOperation(value = "通过id 删除用户", notes = "通过id批量删除")
    @PostMapping("/delBatch")
    public Result<?> delBatch(@RequestBody List<Integer> ids) {
        if (ids == null || ids.size() <= 0) {
            return new Result<>().error(-1, "非法操作!");
        }
        // todo: 登录状态拦截
        boolean flag  = sysUserService.removeBatchByIds(ids);
        if (flag)
            return new Result<>().success();
        else
            return new Result<>().error();
    }

    /**
     *  VO 对象: 通过 id 查询用户信息
     */
    @PostMapping("/getById")
    public Result<SysUserVO> getById(@RequestParam("id") Integer id) {
        if (id == null || id < 0) {
            return new Result<SysUserVO>().error(-1, "非法请求.");
        }
        // todo: 登录才可以操作, token 直接不放行即可
        SysUser sysUser = sysUserService.getById(id);
        if (sysUser == null) {
            return new Result<SysUserVO>().error("用户不存在!");
        }
        SysUserVO userVO = new SysUserVO();
        BeanUtils.copyProperties(sysUser, userVO);
        return new Result<SysUserVO>().success(userVO);
    }
}


